package com.skyz.base.manager;

import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;


import com.skyz.base.util.CacheUtils;

import androidx.annotation.NonNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FileLoggerManager {

    public static int MSG_WHAT_LOOP = 0x59334;

    public static boolean sShowLog = false;

    private final String TAG = getClass().getSimpleName();

    private Application mApplication;

    private final List<FileLog> mFileLogList = new ArrayList<>();

    private final Object object = new Object();

    private final ExecutorService mService = Executors.newSingleThreadExecutor();

    private final Handler mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            mService.execute(new Runnable() {
                @Override
                public void run() {
                    synchronized (object) {
                        if (mFileLogList.isEmpty()) {
                            return;
                        }
                        FileLog fileLog = mFileLogList.get(0);
                        String content = fileLog.getContent();
                        showLog(content);
                        saveLogToFile(fileLog.getLogType(), content, fileLog.isAppend());
                        mFileLogList.remove(0);
                    }
                }
            });
            return true;
        }
    });

    private final SimpleDateFormat mSimpleDateFormatyyyyMMddHHmmss = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);

    private final SimpleDateFormat mSimpleDateFormatyyyyMMdd = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);

    private FileLoggerManager() {
    }

    private static class InstanceHolder {
        private static final FileLoggerManager instance = new FileLoggerManager();
    }

    public static FileLoggerManager getInstance() {
        return InstanceHolder.instance;
    }

    public void init(Application application) {
        mApplication = application;
    }

    private void showLog(String content) {
        if (sShowLog) {
            Log.i(TAG, content);
        }
    }

    public void stop() {
        if (mService == null) {
            return;
        }
        mService.shutdownNow();
    }

    public void logNet(String content) {
        FileLog fileLog = new FileLog(LogType.NET, content, true);
        FileLoggerManager.getInstance().log(fileLog, true);
    }

    public void logCrash(String content) {
        FileLog fileLog = new FileLog(LogType.CRASH, content, true);
        FileLoggerManager.getInstance().log(fileLog, false);
    }

    public void logAction(String content) {
        FileLog fileLog = new FileLog(LogType.ACTION, content, true);
        FileLoggerManager.getInstance().log(fileLog, true);
    }

    public void logOther(String content) {
        FileLog fileLog = new FileLog(LogType.OTHER, content, true);
        FileLoggerManager.getInstance().log(fileLog, true);
    }

    private void log(FileLog fileLog, boolean async) {
        if (fileLog == null) {
            return;
        }
        if (async) {
            synchronized (object) {
                mFileLogList.add(fileLog);
                mHandler.sendEmptyMessage(MSG_WHAT_LOOP);
            }
        } else {
            String content = fileLog.getContent();
            saveLogToFile(fileLog.getLogType(), content, fileLog.isAppend());
        }
    }


    private synchronized void saveLogToFile(LogType logType, String content, boolean append) {
        FileOutputStream fileOutputStream = null;
        try {
            File dir = getLogDir(logType);
            Date date = new Date();
            String fileName = mSimpleDateFormatyyyyMMdd.format(date) + ".txt";
            String time = mSimpleDateFormatyyyyMMddHHmmss.format(date);
            if (dir != null) {
                fileOutputStream = new FileOutputStream(new File(dir, fileName), append);
                String text = time + ":" + content + "\n";
                fileOutputStream.write(text.getBytes(StandardCharsets.UTF_8));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private File getLogDir(LogType logType) {
        if (mApplication == null) {
            return null;
        }
        return new File(CacheUtils.getCacheDirectory(mApplication, logType.name()));
    }

    public enum LogType {
        NET,
        CRASH,
        ACTION,
        OTHER
    }

    public static class FileLog {
        private final LogType mLogType;
        private final String mContent;
        private final boolean mAppend;

        public FileLog(LogType logType, String content, boolean append) {
            this.mLogType = logType;
            this.mContent = content;
            this.mAppend = append;
        }

        public LogType getLogType() {
            return mLogType;
        }

        public String getContent() {
            return mContent;
        }

        public boolean isAppend() {
            return mAppend;
        }
    }

}
